﻿namespace FSpec

open System
open System.Linq
open System.Collections 
open Gallio.Framework.Assertions
open Gallio.Framework
open System.Collections.Generic 
open System.Linq

[<AutoOpen>]
module AssertionHelper = 
    
    let writeContextMessage() =
        let assertionContext = AssertionContext.CurrentContext 
        let test = assertionContext.TestContext.Test 
        let codeElement = test.CodeElement
            
        let testName = if test.Name.StartsWith("it") || test.Name.StartsWith("the") then
                            "Let " + test.Name
                        else
                            test.Name
        let concernName = test.Parent.Parent.Name
        let contextName = test.Parent.Name

        let sb = new System.Text.StringBuilder()
        let log = assertionContext.TestContext.LogWriter.ConsoleInput
        log.WriteLine(
            sb
                .AppendLine(concernName)
                .AppendLine("\t--> " + contextName)
                .AppendLine("\t\t--> " + testName) 
                .ToString()
        )
        log.Flush()
        
    let label (pair:string*'a) = 
        let name, value = pair
        new Gallio.Framework.Assertions.AssertionFailure.LabeledValue(name, value.ToString())

    let verify func =
        AssertionHelper.Verify (new Gallio.Common.Func<AssertionFailure>( func ))
    
    let createFailureFrom description = new AssertionFailureBuilder(description)
    
    let addRawValues 
        expected 
        actual 
        (builder:AssertionFailureBuilder) = 
            builder.AddRawExpectedAndActualValuesWithDiffs(expected, actual)
    
    let addLabelledValues 
        expected 
        actual 
        (builder:AssertionFailureBuilder) = 
            let expectedLabel, exp = expected
            let actualLabel, act = actual
            builder.AddRawLabeledValuesWithDiffs(expectedLabel, exp, actualLabel, act)
    
    let addLabeledValue (value:string*obj) (builder:AssertionFailureBuilder) =
        let valueLabel, v = value
        builder.AddLabeledValue(valueLabel, v.ToString())
    
    let addRawValue
        value
        (builder:AssertionFailureBuilder) =
            builder.AddRawActualValue value
    
    let addException (exp:exn) (builder:AssertionFailureBuilder) =
        builder.AddException(exp)
        
    let setMessage (message:string) (builder:AssertionFailureBuilder) =
        builder.SetMessage message
    
    let shortenStackTrace (builder:AssertionFailureBuilder) =
        let assertionContext = AssertionContext.CurrentContext 
        if assertionContext = null || assertionContext.TestContext = null || assertionContext.TestContext.Test = null then 
            builder
        else
            let test = assertionContext.TestContext.Test 
            let codeElement = test.CodeElement 
            if codeElement.Name.StartsWith("it") || codeElement.Name.StartsWith("the") then
                let data = new Gallio.Common.Diagnostics.StackTraceData(codeElement)
                builder.SetStackTrace( data.Normalize())  
            else
                builder


    let toFailureException (builder:AssertionFailureBuilder) =
        (builder |> shortenStackTrace)
            .ToAssertionFailure()
        
    let format fmt (args:obj list) = 
        let arguments = args.ToArray()
        String.Format(fmt, arguments)